home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / xdme_1.84_src.lha / XDME / Src / edit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-08  |  29.3 KB  |  1,493 lines

  1. /******************************************************************************
  2.  
  3.     MODUL
  4.     $Id: edit.c 1.4 1994/09/09 12:31:30 digulla Exp digulla $
  5.  
  6.     DESCRIPTION
  7.     Everything for editing like DEL, BS, INDENT, DELINE, INSLINE, ...
  8.  
  9.     HISTORY
  10.     14. Nov 1992    ada created
  11.     $Log: edit.c $
  12.  * Revision 1.4  1994/09/09  12:31:30  digulla
  13.  * added new style Prototypes, DEFCMD and DEFHELP
  14.  * fixed a bug in do_join()
  15.  *
  16.  * Revision 1.3  1994/08/30  11:09:32  digulla
  17.  * use BLOCK_MASK over ALL_MASK
  18.  *
  19.  * Revision 1.2  1994/08/19  14:09:10  digulla
  20.  * fixed SetWrMsk()
  21.  * removed dead assignments
  22.  *
  23.  * Revision 1.1  1994/08/13  17:14:04  digulla
  24.  * Initial revision
  25.  *
  26.  
  27. ******************************************************************************/
  28.  
  29. /**************************************
  30.         Includes
  31. **************************************/
  32. #include "defs.h"
  33. #include "clipboard.h"
  34. #define MYDEBUG     0
  35. #include <debug.h>
  36.  
  37.  
  38. /**************************************
  39.         Globale Variable
  40. **************************************/
  41.  
  42.  
  43. /**************************************
  44.       Interne Defines & Strukturen
  45. **************************************/
  46.  
  47.  
  48. /**************************************
  49.         Interne Variable
  50. **************************************/
  51.  
  52.  
  53. /**************************************
  54.        Interne Prototypes
  55. **************************************/
  56.  
  57.  
  58. /*DEFHELP #cmd textedit BACK - backspace, (delete char to left of cursor) */
  59. /*DEFHELP #cmd textedit BS - backspace, (delete char to left of cursor) */
  60. /*DEFHELP #cmd textedit DEL - delete, (deletes char under cursor) */
  61.  
  62. DEFUSERCMD("bs",   0, CF_COK, void, do_bs, (void),;)
  63. DEFUSERCMD("del",  0, CF_COK, void, do_bs, (void),;)
  64. DEFUSERCMD("back", 0, CF_COK, void, do_bs, (void),)
  65. {
  66.     ED     * ep  = Ep;
  67.     RP     * rp  = ep->win->RPort;
  68.     WORD   i,
  69.        col = ep->column;
  70.     Column right;
  71.     BOOL   is_bs = (av[0][0] == 'b');
  72.  
  73.     if ((Current[col] && !is_bs) || (col && is_bs))
  74.     {
  75.     if (is_bs)
  76.     {
  77.         movmem (Current + col, Current + col - 1, Clen - col + 1);
  78.  
  79.         col --;
  80.         ep->column --;
  81.  
  82.     } else
  83.         movmem (Current + col + 1, Current + col, Clen - col);
  84.  
  85.     Clen --;
  86.  
  87.     i = ep->line;
  88.     right = ep->topcolumn + Columns;
  89.  
  90.     if (!Nsu) {                         /* PATCH_NULL [09-Dec-92] : line added */
  91.         if (col < ep->topcolumn)
  92.         {
  93.         text_adjust (FALSE);
  94.         } else
  95.         {
  96.         if (is_inblock (i, right) & BP_INSIDE)
  97.         {
  98.             SetAPen (rp, BLOCK_FPEN(ep));
  99.             SetBPen (rp, BLOCK_BPEN(ep));
  100.         } else
  101.         {
  102.             SetAPen (rp, TEXT_FPEN(ep));
  103.             SetBPen (rp, TEXT_BPEN(ep));
  104.         }
  105.  
  106.         SetWrMsk (rp, BLOCK_MASK(ep));
  107.  
  108.         i -= ep->topline;
  109.  
  110.         ScrollRaster(rp, Xsize, 0,
  111.             COL(col - ep->topcolumn), ROW(i),
  112.             Xpixs, ROW(i + 1) - 1
  113.         );
  114.  
  115.         if (ep->win->WLayer->Flags & LAYERREFRESH)
  116.             OptimizedRefresh (ep);
  117.         else if (Clen >= right)
  118.         {
  119.             right --;
  120.  
  121.             Move (rp, COLT(right - ep->topcolumn), ROWT(i));
  122.             Text (rp, Current + right, 1);
  123.         }
  124.         }
  125.     } /* if !Nsu */             /* PATCH_NULL [09-Dec-92] : line added */
  126.  
  127.     if (!GETF_COMLINEMODE(Ep) && GETF_WORDWRAP(Ep))
  128.         do_reformat(0);
  129.     } else
  130.     {
  131.     SETF_ABORTCOMMAND(Ep,1);
  132.     }
  133. } /* do_bs */
  134.  
  135.  
  136. /*DEFHELP #cmd textedit REMEOL - Remove text under and beyond the cursor. */
  137.  
  138. DEFUSERCMD("remeol", 0, CF_VWM|CF_COK, void, do_remeol, (void),)
  139. {
  140.     Current[Clen = Ep->column] = 0;
  141.  
  142.     text_sync ();
  143.     text_redisplaycurrline ();
  144. } /* do_remeol */
  145.  
  146.  
  147. /*DEFHELP #cmd textedit SPLIT - Split line at cursor */
  148.  
  149. DEFUSERCMD("split", 0, 0, void, do_split, (void),)
  150. {
  151.     UBYTE buf[MAXLINELEN];
  152.     ED    * ep           = Ep;
  153.     RP    * rp           = ep->win->RPort;
  154.     char  onLastLine;
  155.  
  156.     strcpy ((char *)buf, (char *)Current+ep->column);
  157.     Current[Clen = ep->column] = '\0';
  158.  
  159.     text_sync ();
  160.  
  161.     SetAPen (rp, TEXT_BPEN(ep));
  162.     SetWrMsk (rp, BLOCK_MASK(ep));
  163.  
  164.     if (!Nsu)
  165.     RectFill (rp, COL(0), ROW(ep->line-ep->topline),
  166.            Xpixs, ROW(ep->line-ep->topline+1)-1);
  167.  
  168.     SetAPen (rp, TEXT_FPEN(ep));
  169.  
  170.     text_displayseg (ep->line - ep->topline, 1);
  171.  
  172.     onLastLine = (ep->line == ep->lines-1);
  173.     do_downadd ();
  174.  
  175.     if (!onLastLine)
  176.     do_insline ();
  177.  
  178.     strcpy ((char *)Current, (char *)buf);
  179.     Clen = strlen ((char *)Current);
  180.  
  181.     text_sync ();
  182.     text_displayseg (ep->line - ep->topline, 1);
  183.  
  184.     do_up ();
  185. } /* do_split */
  186.  
  187.  
  188. /*DEFHELP #cmd textedit JOIN - join next line to line at cursor */
  189.  
  190. DEFUSERCMD("join", 0, 0, int, do_join, (void),)
  191. {
  192.     int   i = Clen;
  193.     ED * ep = Ep;
  194.  
  195.     /* Check if there is a line below and the length of both lines */
  196.     if (ep->line + 1 < ep->lines &&
  197.         LINELEN(ep,ep->line+1)+i <= MAXLINELEN-2)
  198.     {
  199.     char * ptr;
  200.     int    column = ep->column;
  201.  
  202.     /* Find first nonspace in next line */
  203.     for (ptr=GETTEXT(ep,ep->line+1); *ptr==' ' && *ptr; ptr ++);
  204.  
  205.     if (i && !Current[i]) /* ignore last char if it's \0 */
  206.         i --;
  207.  
  208.     /* Find last char in this line */
  209.     for (; i >= 0 && Current[i] == ' '; i--);
  210.  
  211.     /* Add a space if neccessary */
  212.     if (i >= 0)
  213.     {
  214.         if (Current[i])
  215.         i++;
  216.  
  217.         Current[i ++] = ' ';
  218.     }
  219.  
  220.     /* Copy the line */
  221.     strcpy((char *)Current+i, ptr);
  222.  
  223.     /* new length */
  224.     Clen = strlen ((char *)Current);
  225.  
  226.     /* redisplay */
  227.     text_sync ();
  228.     text_displayseg (ep->line - ep->topline, 1);
  229.  
  230.     i = text_lineno ();
  231.  
  232.     do_down ();
  233.     do_deline ();
  234.  
  235.     if (i != text_lineno ())
  236.         do_up ();
  237.  
  238.     /* 29-11-94 - fix for shortlines */
  239.     if (ep->column != column)
  240.     {
  241.         ep->column = column;
  242.         text_adjust (FALSE);
  243.     }
  244.     return(1);
  245.     }
  246.  
  247.     return(0);
  248. } /* do_join */
  249.  
  250.  
  251. /*
  252.  * n == -1  :    force reformat entire paragraph
  253.  * n ==  0  :    only until line equalizes (from text_write())
  254.  *
  255.  * What is a paragraph?   A paragraph ends whenever the left justification
  256.  * gets larger, or on a blank line.
  257.  */
  258.  
  259. /*DEFHELP #cmd textedit,format REFORMAT - reformat paragraph using the margin. */
  260.  
  261. DEFUSERCMD("reformat", 0, 0, void, do_reformat, (int n),)
  262. {
  263.     char * str;
  264.     ED     * ep = Ep;
  265.     RP     * rp = ep->win->RPort;
  266.     int    nlok;   /* Next Line ok ? */
  267.     int    lnsc;   /* LastNS of Current */
  268.     int    fnst;   /* FirstNS of next Line */
  269.     int    fnsc;   /* FirstNS of Current */
  270.     int    column  = ep->column;
  271.     int    srow    = ep->line;
  272.     int    crow    = srow;
  273.     int    erow    = srow;
  274.     WORD   dins    = 0;     /* relative insert lines/delete lines    */
  275.     char   moded   = 0;     /* any modifications done at all?    */
  276.     char   checked = 0;     /* for cursor positioning.        */
  277.     Line   old_top;
  278.     char   slin_bak;
  279.     slin_bak = GETF_SLINE( ep );
  280.     SETF_SLINE( ep, 0 );
  281.  
  282.     if (ep->config.margin == 0)
  283.     ep->config.margin = 75;
  284.  
  285.     Nsu ++;
  286.  
  287.     old_top = ep->topline;
  288.  
  289.     for (;;)
  290.     {
  291.     str = GETTEXT(ep,ep->line+1);
  292.     fnst = 0;
  293.     fnsc = firstns((char *)Current);
  294.     nlok = (ep->line + 1 < ep->lines && fnsc >= (fnst=firstns(str)));
  295.     if (ep->config.wwcol >= 0)
  296.         fnst = fnsc = ep->config.wwcol;
  297.     if (nlok && str[0] == 0)
  298.         nlok = 0;
  299.     lnsc = lastns((char *)Current);
  300.     if (lnsc < ep->config.margin)
  301.     {    /* space at end of line for marg-lnsc-2 letter word   */
  302.         if (nlok == 0)        /* but no more data to joinup   */
  303.         break;          /* done */
  304.         if (ep->config.margin - lnsc - 2 >= wordlen(str+fnst))
  305.         {
  306.         ep->column = 0;
  307.         Clen = lastns((char *)Current);
  308.         if (Current[Clen])
  309.             ++Clen;
  310.         moded = 1;
  311.         --dins;
  312.         if (do_join())
  313.             continue;
  314.         ++dins;
  315.  
  316.         error ("reformat:\nMargin too big");
  317.         break;
  318.         }
  319.         if (n == 0)        /* if couldn't mod line, and text_write, don't update any more */
  320.         break;
  321.         do_down ();
  322.         erow = ep->line;
  323.         continue;
  324.     }
  325.                 /* no space, need to split    */
  326.                 /* find start of prev word    */
  327.     for (;;)
  328.     {
  329.         int i = lnsc;
  330.         while (i && Current[i] != ' ')
  331.         --i;
  332.         lnsc = i;
  333.         if (i >= ep->config.margin)
  334.         {
  335.         while (i && Current[i] == ' ')
  336.             --i;
  337.         if (i < ep->config.margin)
  338.             break;
  339.         lnsc = i;
  340.         } else
  341.         break;
  342.     }
  343.  
  344.     /* Word too long */
  345.     if (wordlen((char *)Current+lnsc) >= ep->config.margin)
  346.     {
  347.         error ("reformat:\nWord too long");
  348.         break;
  349.     }
  350.  
  351.     if (lnsc)
  352.     {          /* ok to split at word          */
  353.         ++lnsc;
  354.         ++dins;
  355.         ep->column = lnsc;
  356.         do_split (); /* Split at point LNSC          */
  357.         do_down ();          /* must insert proper amount?   */
  358.         {
  359.         int indent = (nlok == 0) ? fnsc : fnst;
  360.         if (ep->config.wwcol >= 0)
  361.             indent = ep->config.wwcol;
  362.         if (!checked)
  363.         {
  364.             checked = 1;
  365.             if (lnsc <= column)
  366.             {    /* if split before cursor   */
  367.             column = column - ep->column + indent;
  368.             ++crow;
  369.             }
  370.         }
  371.         if (Clen + indent < MAXLINELEN-3)
  372.         {
  373.             movmem(Current, Current + indent,
  374.                 strlen((char *)Current)+1);
  375.             setmem(Current, indent, ' ');
  376.             Clen += indent;
  377.         }
  378.         }
  379.         erow = ep->line;
  380.         continue;
  381.     }
  382.  
  383.     if (n == 0)
  384.         break;
  385.  
  386.     do_down ();
  387.     }
  388.  
  389.     if (column < 0 || column > 200)
  390.     column = 0;
  391.  
  392.     if (srow >= ep->lines)
  393.     goto ra;
  394.  
  395.     Nsu --;
  396.  
  397.     if (old_top != ep->topline)
  398.     {
  399.     scroll_display (0, ep->topline-old_top,
  400.         ep->topcolumn, ep->topline,
  401.         ep->topcolumn + Columns, ep->topline + Lines);
  402.     }
  403.  
  404.     if (dins || srow < ep->topline || srow >= ep->topline + Lines)
  405.     {
  406. ra:
  407.     text_sync ();
  408.  
  409.     ep->line = crow;
  410.     ep->column = column;
  411.  
  412.     text_load ();
  413.  
  414.     text_adjust (TRUE);
  415.     } else
  416.     {
  417.     text_sync ();
  418.  
  419.     ep->line = crow;
  420.     ep->column = column;
  421.  
  422.     text_load ();
  423.  
  424.     if (erow != srow)
  425.     {
  426.         if (!text_adjust (FALSE))
  427.         {
  428.         if (erow - ep->topline > Lines)
  429.             erow = ep->topline + Lines;
  430.  
  431.         SetAPen(rp, TEXT_BPEN(ep));
  432.         SetWrMsk (rp, BLOCK_MASK(ep));
  433.  
  434.         RectFill(rp, COL(0), ROW(srow - ep->topline),
  435.             Xpixs, ROW(erow - ep->topline + 1)-1);
  436.  
  437.         SetAPen(rp, TEXT_FPEN(ep));
  438.  
  439.         text_displayseg(srow - ep->topline, erow - srow + 1);
  440.         }
  441.     } else
  442.     {
  443.         if (moded)
  444.         text_redisplaycurrline ();
  445.     }
  446.     }
  447.     if (column > Clen)
  448.     {
  449.     setmem(Current+Clen, column - Clen, ' ');
  450.     Current[column] = 0;
  451.     }
  452.     ep->column = column;
  453.  
  454.     SETF_SLINE( ep, slin_bak);
  455. } /* do_reformat */
  456.  
  457.  
  458. /*DEFHELP #cmd textedit INSLINE - insert line */
  459.  
  460. DEFUSERCMD("insline", 0, 0, void, do_insline, (void),)
  461. {
  462.     LINE ptr;
  463.     ED *ep = Ep;
  464.  
  465.     SETF_MODIFIED(ep,1);
  466.  
  467.     text_sync ();
  468.  
  469.     if (makeroom (32))
  470.     {
  471.     ptr = allocline (1);
  472.  
  473.     bmovl(ep->list+ep->line, ep->list+ep->line+1,ep->lines-ep->line);
  474.     SETLINE(ep,ep->line,ptr);
  475.  
  476.     ep->lines ++;
  477.  
  478.     if (ActualBlock.ep == ep)
  479.     {
  480. #if 1 /* PATCH_NULL 27-09-94  */
  481.         if (ep->line <= ActualBlock.end_line)
  482.         set_block_end (ActualBlock.end_line+1, NO_CHANGE);
  483.  
  484.         if (ep->line <= ActualBlock.start_line)
  485.         set_block_start (ActualBlock.start_line+1, NO_CHANGE);
  486. #else
  487.         if (ep->line <= ActualBlock.start_line)
  488.         MOVE_BLOCKMARK ( +1, 0 );
  489.         else
  490.         if (ep->line <= ActualBlock.end_line)
  491.         set_block_end (ActualBlock.end_line+1, NO_CHANGE);
  492. #endif
  493.     }
  494.     } else
  495.     {
  496.     nomemory ();
  497.     }
  498.  
  499.     text_load ();
  500.  
  501.     if (Nsu == 0)
  502.     {
  503.     scroll_display (0, -1, 0, ep->line, MAXLINELEN, ep->topline+Lines);
  504.     text_displayseg (ep->line - ep->topline, 1);
  505.     }
  506. } /* do_insline */
  507.  
  508.  
  509. /*DEFHELP #cmd textedit DELINE - delete line */
  510.  
  511. DEFUSERCMD("deline", 0, 0, void, do_deline, (void),)
  512. {
  513.     int delline, eline;
  514.     ED *ep = Ep;
  515.  
  516.     /* store line for later UNDO */
  517.     strcpy ((char *)Deline, (char *)Current);
  518.  
  519.     if (ep->lines > 1)
  520.     {
  521.     SETF_MODIFIED(ep,1);
  522.  
  523.     text_sync ();
  524.  
  525.     /* remove line */
  526.     freeline (GETLINE(ep,ep->line));
  527.     bmovl (ep->list+ep->line+1, ep->list+ep->line, ep->lines-ep->line-1);
  528.  
  529.     /* adjust block */
  530.     if (ActualBlock.ep == ep)
  531.     {
  532. #if 0 /* PATCH_NULL 27-09-94  */
  533.         if (ep->line < ActualBlock.start_line)
  534.         set_block_start (ActualBlock.start_line-1, NO_CHANGE);
  535.  
  536.         if (ep->line <= ActualBlock.end_line)
  537.         set_block_end (ActualBlock.end_line-1, NO_CHANGE);
  538.  
  539.         /* if we just deleted the last line of the block, clear it */
  540.         if (ActualBlock.end_line < ActualBlock.start_line)
  541.         unblock ();
  542. #else
  543. // it would really be great, if we could say something like
  544. // #define uplast(which) block. ## which ## _column = INFRONT_OF_LINE;
  545. // where that IN_FRONT_OF was e.g. a '-3'
  546. // or alternatively, a PAST_END (instead of the 500) would be
  547. // a little bit more convenient since Aaron is working on longer lines
  548. #define uplast(which) do{ -- block. ## which ## _line; block. ## which ## _column = 500; }while(0)
  549.         Block block;
  550.         get_block(&block);
  551.  
  552.         if (ep->line == block.end_line)
  553.          uplast( end );
  554.         else if (ep->line < block.end_line)
  555.         -- block.end_line;
  556.  
  557.         if (ep->line == block.start_line)
  558.         uplast( start );
  559.         else if (ep->line < block.start_line)
  560.         -- block.start_line;
  561.  
  562.         if ((block.start_line > block.end_line) ||
  563.            ((block.start_line == block.end_line) &&
  564.         (block.start_column > block.end_column)))
  565.         unblock();
  566.         else if (ep->line <= ActualBlock.end_line)
  567.           {
  568.         set_block(&block);
  569.         //displayblock (1);
  570.           }
  571. //printf ("block: %d (%2d,%3d)-(%2d,%3d)\n", block.type, block.start_line, block.start_column, block.end_line, block.end_column);
  572.  
  573. #if 0
  574.         if ((ep->line < ActualBlock.end_line)) {
  575.             if (ep->line == ActualBlock.start_line)
  576.             set_block_start (NO_CHANGE, 0);
  577.             set_block_end (ActualBlock.end_line-1, NO_CHANGE);
  578.         } else
  579.         if ((ep->line == ActualBlock.end_line))
  580.         if ((ActualBlock.end_line == ActualBlock.start_line))
  581.             unblock ();
  582.         else
  583.             set_block_end (NO_CHANGE, 0);
  584. #endif
  585. #endif
  586.     }
  587.  
  588.     /* remember line we deleted */
  589.     delline = ep->line;
  590.  
  591.     /* line was last one */
  592.     if (ep->line >= --ep->lines)
  593.     {
  594.         /* move up one line */
  595.         --ep->line;
  596.  
  597.         /* get the line into current */
  598.         text_load ();
  599.  
  600.         /* line now below topline ? */
  601.         if (ep->line < ep->topline)
  602.         {
  603.         /* update screen if allowed */
  604.         if (!Nsu)
  605.         {
  606.             /* find new position */
  607.             ep->topline = ep->line - (Lines>>1);
  608.  
  609.             if (ep->topline < 0)
  610.             ep->topline = 0;
  611.  
  612.             text_redisplay ();
  613.         }
  614.  
  615.         return;
  616.         }
  617.     }
  618.  
  619.     /* get line */
  620.     text_load ();
  621.  
  622.     /* update display */
  623.     if (!Nsu)
  624.     {
  625.         eline = ep->topline + Lines - 1;
  626.  
  627.         if (ep->lines < eline)
  628.         eline = ep->lines +1;
  629.  
  630.         scroll_display (0, 1, ep->topcolumn, delline,
  631.                   ep->topcolumn+Columns-1, eline);
  632.     }
  633.     } else
  634.     {
  635.     /* no more lines in the text */
  636.     do_firstcolumn ();
  637.     do_remeol ();
  638.     SETF_MODIFIED(ep,0);
  639.     }
  640. } /* do_deline */
  641.  
  642.  
  643. /*DEFHELP #cmd textedit TLATE how - Modify character under cursor. */
  644.  
  645. DEFUSERCMD("tlate", 1, CF_COK, void, do_tlate, (void),)
  646. {
  647.     UBYTE * ptr = av[1];
  648.     ED      * ep    = Ep;
  649.     UBYTE   c    = Current[ep->column];
  650.  
  651.     if (c == 0)
  652.     c = ' ';
  653.  
  654.     switch (*ptr)
  655.     {
  656.     case '+':
  657.         c += strtol ((char *)ptr+1, NULL, 0);
  658.         break;
  659.  
  660.     case '-':
  661.         c -= strtol ((char *)ptr+1, NULL, 0);
  662.         break;
  663.  
  664.     case '"':
  665.         c = ptr[1];
  666.         break;
  667.  
  668.     case 'u':
  669.     case 'U':
  670.         c = toupper (c);
  671.         break;
  672.  
  673.     case 'l':
  674.     case 'L':
  675.         c = tolower (c);
  676.         break;
  677.  
  678.     default:
  679.         c = strtol ((char *)ptr, NULL, 0);
  680.     }
  681.  
  682.     if (c)
  683.     {
  684.     if (Current[ep->column] == 0)
  685.     {
  686.         Clen = ep->column + 1;
  687.         Current[Clen] = 0;
  688.     }
  689.  
  690.     if (!Nsu && Current[ep->column] != c)
  691.     {
  692.         LINE text_line;
  693.  
  694.         SETF_MODIFIED(ep,TRUE);
  695.  
  696.         Current[ep->column] = c;    /* Change char */
  697.  
  698.         /* get the actual line */
  699.         text_line = GETLINE(ep,ep->line);
  700.  
  701.         /* if the char fits into the line, just copy it (ie. avoid
  702.            text_sync(). Else call text_sync() */
  703.  
  704.         if (ep->column < LENGTH(text_line))
  705.         {
  706.         char * ptr;
  707.  
  708.         /* change it */
  709.         ptr = CONTENTS(text_line);
  710.         ptr[ep->column] = c;
  711.         }
  712.         else
  713.         text_sync ();
  714.  
  715.         /* Delete the character on screen. First, find the color
  716.            we need for this operation, then draw over it */
  717.         if (is_inblock (ep->line, ep->column) & BP_INSIDE)
  718.         SetAPen (ep->win->RPort, BLOCK_BPEN(ep));
  719.         else
  720.         SetAPen (ep->win->RPort, TEXT_BPEN(ep));
  721.  
  722.         /* redraw that character */
  723.         {
  724.         UWORD lin, col;
  725.  
  726.         col = ep->column - ep->topcolumn;
  727.         lin = ep->line - ep->topline;
  728.  
  729.         SetWrMsk (ep->win->RPort, BLOCK_MASK(Ep));
  730.         RectFill (ep->win->RPort, COL(col), ROW(lin),
  731.                     COL(col+1)-1, ROW(lin+1)-1);
  732.         SetWrMsk (ep->win->RPort, ALL_MASK);
  733.         }
  734.  
  735.         redraw_textlineseg (ep->line, ep->column, ep->column+1);
  736.     }
  737.     }
  738. } /* do_tlate */
  739.  
  740.  
  741. /*DEFHELP #cmd textedit,format JUSTIFY how - simple text justification. */
  742.  
  743. DEFUSERCMD("justify", 1, 0, void, do_justify, (void),)
  744. {
  745.     ED *ep = Ep;
  746.     WORD  firstnb, lastnb, i, n, fill, c, sp;
  747.     WORD  changed = FALSE;
  748.  
  749.     firstnb = firstns((char *)Current);
  750.     lastnb = lastns((char *)Current);
  751.  
  752.     if (ep->config.margin >= MAXLINELEN)
  753.     {
  754.     error ("%s:\nMargin (%ld) too large\n(max %ld)\n",
  755.         av[0], ep->config.margin, MAXLINELEN-1);
  756.     return;
  757.     }
  758.  
  759.     if (firstnb >= lastnb) /* line empty ? */
  760.     return;
  761.  
  762.     switch (tolower (av[1][0]))
  763.     {
  764.     case 'l':
  765.         /* remove all firstnb spaces */
  766.         if (firstnb)
  767.         {
  768.         Clen -= firstnb;
  769.         memmove (Current, Current+firstnb, Clen+1);
  770.         changed = TRUE;
  771.         }
  772.         break;
  773.  
  774.     case 'r':
  775.         /* insert/remove spaces, so the last character is at margin */
  776.         if (n = (ep->config.margin - lastnb))
  777.         goto insrem;
  778.  
  779.         break;
  780.  
  781.     case 'c':
  782.         /* width of line */
  783.         n = (lastnb - firstnb + 1);
  784.  
  785.         if (n < ep->config.margin)
  786.         {
  787.         n = (ep->config.margin/2) - (n+1)/2 - firstnb;
  788.  
  789.         if (n) /* insert/remove n spaces */
  790.         {
  791. insrem:
  792.             changed = TRUE;
  793.  
  794.             if (n > 0) /* insert */
  795.             {
  796.             memmove (Current+n, Current, Clen+1);
  797.             memset (Current, ' ', n);
  798.             }
  799.             else /* remove */
  800.             {
  801.             /* n is bigger than the number of spaces at this
  802.                point, because otherwise the length of the
  803.                line would have been bigger than the margin.
  804.                And remember: n is NEGATIVE */
  805.  
  806.             memmove (Current, Current-n, Clen+n+1);
  807.             }
  808.  
  809.             Clen += n;
  810.         }
  811.         }
  812.  
  813.         break;
  814.  
  815.     case 'f':
  816.         n = 0;
  817.         i = firstnb;
  818.  
  819.         while (i <= lastnb)
  820.         {
  821.         while ((c = Current[i]) && c != ' ')
  822.             i++;
  823.         if (i <= lastnb)
  824.         {
  825.             n++;
  826.             while (Current[i] == ' ')
  827.             i++;
  828.         }
  829.         }
  830.  
  831.         fill = ep->config.margin - lastnb - 1;
  832.         i = firstnb;
  833.         Current[lastnb + 1] = 0;
  834.  
  835.         if (n > 0 && fill > 0)
  836.         changed = TRUE;
  837.  
  838.         while (n > 0 && fill > 0 && Current[i])
  839.         {
  840.         while ((c = Current[i]) && c != ' ')
  841.             i++;
  842.         sp = fill / n;
  843.         movmem (&Current[i], &Current[i + sp],
  844.             strlen((char *)&Current[i]) + 1);
  845.         memset ((char *)&Current[i], ' ', sp);
  846.         while (Current[i] == ' ')
  847.             i++;
  848.         fill -= sp;
  849.         n--;
  850.         }
  851.  
  852.         break;
  853.  
  854.     default:
  855.         error ("%s:\nunknown justification\n%s", av[0], av[1]);
  856.         break;
  857.     }
  858.  
  859.     if (changed)
  860.     {
  861.     text_sync ();
  862.     text_redisplaycurrline ();
  863.     }
  864. } /* do_justify */
  865.  
  866.  
  867. /*DEFHELP #cmd textedit UNJUSTIFY - removes extra spaces in a line */
  868.  
  869. DEFUSERCMD("unjustify", 0, 0, void, do_unjustify, (void),)
  870. {
  871.     WORD  i, j, waswhite = FALSE;
  872.     UBYTE c;
  873.  
  874.     for (i = 0; Current[i] == ' '; i++);
  875.  
  876.     for (j = i; Current[i]; i++)
  877.     {
  878.     c = Current[j] = Current[i];
  879.  
  880.     if (c != ' ' || !waswhite)
  881.         j++;
  882.  
  883.     waswhite = (c == ' ');
  884.     }
  885.  
  886.     Current[j] = 0;
  887.  
  888.     if (i != j)
  889.     {
  890.     text_sync ();
  891.     text_redisplaycurrline ();
  892.     }
  893. } /* do_unjustify */
  894.  
  895.  
  896. /*DEFHELP #cmd textedit INDENT what how - indent text. @{B}what@{UB} specifies what to indent and @{B}how@{UB} how to indent it. */
  897.  
  898. DEFUSERCMD("indent", 2, CF_BLK|0, void, do_indent, (void),)
  899. {
  900.     Line   start,
  901.        end;
  902.     Column column;
  903.     int    indent,
  904.        dir,
  905.        align,
  906.        len,
  907.        curr_indent,
  908.        leading,
  909.        trailing,
  910.        t;
  911.     char * ptr;
  912.     RP     * rp;
  913.     LINE * linelist;
  914.  
  915.     /* decode range */
  916.     ptr = av[1];
  917.  
  918.     start = end = -1;
  919.  
  920.     while (*ptr)
  921.     {
  922.     if (*ptr == '.')
  923.     {
  924.         start = end = Ep->line;
  925.         break;
  926.     } else if (isdigit(*ptr))
  927.     {
  928.         if (start == -1)
  929.         start = atoi (ptr);
  930.         else end = atoi (ptr);
  931.  
  932.         while (isdigit(*ptr)) ptr ++;
  933.  
  934.         ptr --;
  935.     } else if (*ptr == '$')
  936.     {
  937.         if (start == -1)
  938.         start = get_pong (*ptr - '0');
  939.         else
  940.         end = get_pong (*ptr - '0');
  941.     } else if (*ptr == 'b')
  942.     {
  943.         if (!block_ok())
  944.         {
  945.         error ("indent block:\nNo block specified");
  946.         return ;
  947.         }
  948.  
  949.         if (!ptr[1])
  950.         {
  951.         start = ActualBlock.start_line;
  952.         end = ActualBlock.end_line;
  953.         } else
  954.         {
  955.         ptr ++;
  956.  
  957.         if (*ptr == 's')
  958.             indent = ActualBlock.start_line;
  959.         else
  960.             indent = ActualBlock.end_line;
  961.  
  962.         if (start == -1)
  963.             start = indent;
  964.         else
  965.             end = indent;
  966.         }
  967.     } else if (*ptr == 't')
  968.     {
  969.         start = 1;
  970.         end = Ep->lines;
  971.     } else if (*ptr == '_')
  972.     {
  973.         if (start == -1)
  974.         start = Ep->lines;
  975.         else
  976.         end = Ep->lines;
  977.     }
  978.  
  979.     ptr ++;
  980.     } /* while (*ptr) */
  981.  
  982.     if (start == -1)
  983.     {
  984.     error ("indent:\ncannot evaluate start-line");
  985.     return ;
  986.     }
  987.  
  988.     if (end == -1) end = start;
  989.  
  990.     if (start > end)
  991.     {
  992.     start ^= end;        /* Swap ! 8-O */
  993.     end   ^= start;
  994.     start ^= end;
  995.     }
  996.  
  997.     /* Now find out how to indent */
  998.  
  999.     ptr = av[2];
  1000.  
  1001.     dir = 1;        /* indent, i.e. insert spaces */
  1002.     align = 0;        /* just insert `indent' spaces */
  1003.     indent = -1;
  1004.     column = 0;
  1005.  
  1006.     while (*ptr)
  1007.     {
  1008.     if (*ptr == '-')
  1009.         dir = -1;        /* outdent line, i.e. delete spaces */
  1010.     else if (*ptr == '.')
  1011.         align = 1;        /* align line to a multiple of `indent' */
  1012.     else if (*ptr == 't')
  1013.         indent = Ep->config.tabstop;
  1014.     else if (isdigit(*ptr))
  1015.     {
  1016.         indent = atoi (ptr);
  1017.  
  1018.         while (isdigit(*ptr)) ptr++;
  1019.         ptr --;
  1020.     } else if (*ptr == 'c')
  1021.         column = Ep->column;
  1022.  
  1023.     ptr ++;
  1024.     } /* while (*ptr) */
  1025.  
  1026.     if (indent == -1)
  1027.     {
  1028.     error ("indent:\nCannot evaluate indent-amount");
  1029.     return ;
  1030.     }
  1031.  
  1032.     text_sync ();
  1033.  
  1034.     /* Note : If the line contains less spaces than indent specifies and
  1035.        the user wants to outdent, the line is left-aligned, i.e. no chars
  1036.        except spaces are deleted ! This is also true for indent, i.e. no
  1037.        chars are moved over the right border (MAXLINELEN chars). */
  1038.  
  1039.     linelist = Ep->list + start;
  1040.  
  1041.     for (t=start; t <= end; t ++, linelist ++)
  1042.     {
  1043.     strcpy (Current, linelist[0]);
  1044.     Clen = strlen (Current);
  1045.  
  1046.     if (Clen <= column) continue;
  1047.  
  1048.     ptr = Current + column;
  1049.  
  1050.     while (*ptr == ' ') ptr ++;
  1051.  
  1052.     if (!*ptr) continue;          /* Empty line */
  1053.  
  1054.     leading  = (int)ptr - (int)Current;
  1055.     trailing = MAXLINELEN-1 - Clen;
  1056.  
  1057.     /* Should I align the line to a multiple of indent or just
  1058.         insert/delete indent spaces ? */
  1059.     if (align)
  1060.     {
  1061.         /* use appropriate difference */
  1062.         if (dir > 0)
  1063.         curr_indent = indent - (leading % indent);
  1064.         else
  1065.         {
  1066.         curr_indent = leading % indent;
  1067.  
  1068.         if (!curr_indent)
  1069.             curr_indent = indent;
  1070.         }
  1071.     } else curr_indent = indent;
  1072.  
  1073.     len = strlen (ptr) + 1;
  1074.  
  1075.     if (dir > 0)
  1076.     {
  1077.         if (trailing < curr_indent)
  1078.         curr_indent = trailing;
  1079.  
  1080.         if (!curr_indent) continue;
  1081.  
  1082.         movmem (ptr, ptr+curr_indent, len);
  1083.         setmem (ptr, curr_indent, ' ');
  1084.     } else
  1085.     {
  1086.         if (leading < curr_indent)
  1087.         curr_indent = leading;
  1088.  
  1089.         if (!curr_indent) continue;
  1090.  
  1091.         movmem (ptr, ptr-curr_indent, len);
  1092.     }
  1093.  
  1094.     Clen = strlen (Current);
  1095.  
  1096. #ifdef DEBUG
  1097. printf ("Old len %d  New Len %d     BlenOld %d  BlenNew %d\n",
  1098.     len, Clen, ((len + 8) & ~7), ((Clen + 8) & ~7));
  1099. #endif
  1100.  
  1101.     /* Find out if we have to allocate new memory */
  1102.     /* Clen is total length in bytes while len is only strlen() */
  1103.     /* TODO: Ain't work yet */
  1104.     /*if ((((Clen + 8) & ~7) != ((len + 8) & ~7)))
  1105.     {*/
  1106.         ptr = allocline (Clen + 1);
  1107.  
  1108.         if (!ptr)
  1109.         {
  1110.         nomemory ();
  1111.         break;
  1112.         }
  1113.  
  1114.         freeline (linelist[0]);
  1115.         linelist[0] = ptr;
  1116.     /*}*/
  1117.  
  1118.     strcpy (ptr, Current);
  1119.     } /* for (t = start; t <= end; t ++, linelist ++) */
  1120.  
  1121.     SETF_MODIFIED(Ep,1);
  1122.  
  1123.     text_load ();
  1124.  
  1125.     /* Don't display if there is nothing to display */
  1126.     if (end < Ep->topline)
  1127.     return;
  1128.  
  1129.     if (start < Ep->topline)
  1130.     {
  1131.     start = 0;
  1132.     t = end - Ep->topline +1;
  1133.     }
  1134.     else
  1135.     {
  1136.     t = end - start +1;
  1137.     start -= Ep->topline;
  1138.  
  1139.     if (start >= Lines)
  1140.         return;
  1141.     }
  1142.  
  1143.     if (start+t > Lines)
  1144.     t = Lines-start;
  1145.  
  1146.     if (!Nsu)
  1147.     {
  1148.     rp = Ep->win->RPort;
  1149.  
  1150.     end = start + t-1;
  1151.  
  1152.     /* only clear area, if there is a line outside the block */
  1153.     if (!is_inblock (start + Ep->topline, -1) ||
  1154.         !is_inblock (end + Ep->topline, -1))
  1155.     {
  1156.         SetAPen (rp, TEXT_BPEN(Ep));
  1157.         SetWrMsk (rp, BLOCK_MASK(Ep));
  1158.         RectFill (rp, Xbase, ROW(start), Xpixs, ROW(start+t)-1);
  1159.     }
  1160.  
  1161.     if (!text_sync ())
  1162.         text_displayseg (start, t);
  1163.     }
  1164. } /* do_indent */
  1165.  
  1166.  
  1167. /*DEFHELP #cmd textedit INSLINES n - insert @{B}n@{UB} lines at once */
  1168.  
  1169. DEFUSERCMD("inslines", 1, 0, void, do_inslines, (void),)
  1170. {
  1171.      int lines = atoi (av[1]);
  1172.  
  1173.      if (lines <= 0) return;
  1174.  
  1175.      while (lines)
  1176.      {
  1177.       do_insline ();
  1178.       lines --;
  1179.      }
  1180.  
  1181. } /* do_inslines */
  1182.  
  1183.  
  1184. /*DEFHELP DELETE - delete characters upto the next blank (if on a blank) or to the next non-blank (if on non-blank) */
  1185.  
  1186. DEFUSERCMD("delete", 0, CF_COK, void, do_delete, (void),)
  1187. {
  1188.     char * ptr, * hptr;
  1189.  
  1190.     hptr = ptr = Current + Ep->column;
  1191.  
  1192.     if (!*hptr)
  1193.     return;
  1194.  
  1195.     if (*hptr == ' ')
  1196.     while (*hptr == ' ') hptr ++;
  1197.     else
  1198.     while (*hptr != ' ') hptr ++;
  1199.  
  1200.     memmove (ptr, hptr, strlen (hptr)+1);
  1201.  
  1202.     text_sync ();
  1203.     text_redisplaycurrline ();
  1204. } /* do_delete */
  1205.  
  1206.  
  1207. /*DEFHELP #cmd textedit DELINES n - delete @{B}n@{UB} lines */
  1208.  
  1209. DEFUSERCMD("delines", 1, 0, void, do_delines, (void),)
  1210. {
  1211.      int t;
  1212.  
  1213.      t = atoi (av[1]);
  1214.  
  1215.      for ( ; t >= 0; t--)
  1216.       do_deline ();
  1217. } /* do_delines */
  1218.  
  1219.  
  1220. /*
  1221.  *  Commands submitted by Markus Wenzel
  1222.  */
  1223.  
  1224. /*DEFHELP #cmd misc UNDELINE - insert most recently deleted line (only last line saved) */
  1225.  
  1226. DEFUSERCMD("undeline", 0, 0, void, do_undeline, (void),)
  1227. {
  1228.    do_insline ();
  1229.    text_load ();
  1230.  
  1231.    strcpy((char *)Current, (char *)Deline);
  1232.  
  1233.    text_sync ();
  1234.    text_displayseg (Ep->line - Ep->topline, 1);
  1235. } /* do_undeline */
  1236.  
  1237.  
  1238. /*DEFHELP #cmd block,clip CLIPINS - Insert current contents of clipboard in the text */
  1239.  
  1240. DEFUSERCMD("clipins", 0, CF_COK, void, do_clipins, (void),)
  1241. {
  1242.     struct IOClipReq * ior;
  1243.     struct cbbuf * buf;
  1244.     LONG    lines;
  1245.     BOOL    failed = 0;
  1246.     ED      * ep       = Ep;
  1247.  
  1248.     if (!(ior = CBOpen (0)) )
  1249.     return;
  1250.  
  1251.     if (CBQueryFTXT (ior))
  1252.     {
  1253.     buf = CBReadCHRS (ior);
  1254.  
  1255.     if (buf)
  1256.     {
  1257.         UBYTE line[MAXLINELEN];
  1258.         UBYTE * ptr1, * ptr2;
  1259.         LINE ptr;
  1260.         int len;
  1261.  
  1262.         ptr2 = line;
  1263.         ptr1 = buf->mem;
  1264.  
  1265.         while (*ptr1 && *ptr1 != '\n')
  1266.         *ptr2 ++ = *ptr1 ++;
  1267.  
  1268.         *ptr2 = 0;
  1269.  
  1270.         text_write (line);
  1271.  
  1272.         if (*ptr1)
  1273.         {
  1274.         do_split ();
  1275.         do_down ();
  1276.         do_firstcolumn ();
  1277.  
  1278.         lines = ep->lines;
  1279.  
  1280.         for (ptr1 ++; *ptr1; )
  1281.         {
  1282.             ptr2 = line;
  1283.             len = 0;
  1284.  
  1285.             while (*ptr1 && *ptr1 != '\n')
  1286.             {
  1287.             *ptr2 ++ = *ptr1 ++;
  1288.             len ++;
  1289.             }
  1290.  
  1291.             *ptr2 = 0;
  1292.             len ++;
  1293.  
  1294.             if (*ptr1)
  1295.             ptr1 ++;
  1296.             else
  1297.             {
  1298.             text_write (line);
  1299.             break;
  1300.             }
  1301.  
  1302.             if (makeroom(256) && (ptr = allocline(len)))
  1303.             {
  1304.             SETLINE(ep,ep->lines,ptr);
  1305.             ep->lines ++;
  1306.  
  1307.             movmem(line, ptr, len);
  1308.             }
  1309.             else
  1310.             {
  1311.             set_window_params ();
  1312.             nomemory ();
  1313.             failed = 1;
  1314.             break;
  1315.             }
  1316.         }
  1317.  
  1318.         if (!failed && lines <= ep->lines - 1)
  1319.         {
  1320.             Block block;
  1321.  
  1322.             /* INSFILE: move text to correct position */
  1323.             block.ep         = ep;
  1324.             block.start_line = lines;
  1325.             block.end_line   = ep->lines - 1;
  1326.             block.type         = BT_LINE;
  1327.  
  1328.             displayblock (0);
  1329.             set_block (&block);
  1330.             do_bmove ();
  1331.         }
  1332.         } /* more than one line */
  1333.  
  1334.         window_title ();
  1335.  
  1336.         CBFreeBuf (buf);
  1337.     }
  1338.  
  1339.     CBReadDone (ior);
  1340.     }
  1341.  
  1342.     CBClose (ior);
  1343. } /* do_clipins */
  1344.  
  1345.  
  1346. /*DEFHELP SPACE - inserts a single space no matter what insertmode is set to */
  1347.  
  1348. DEFUSERCMD("space", 0, CF_COK, void, do_space, (void),)
  1349. {
  1350.     ED * ep = Ep;
  1351.     int  insmode = GETF_INSERTMODE(ep);
  1352.  
  1353.     SETF_INSERTMODE(ep,1);
  1354.     text_write (" ");
  1355.     SETF_INSERTMODE(ep,insmode);
  1356. } /* do_space */
  1357.  
  1358.  
  1359. /*DEFHELP #cmd textedit,movement RETURN - if AUTOINDENT is off: (FIRST DOWNADD) else insert line, split current line and indent like last line above. */
  1360.  
  1361. DEFUSERCMD("return", 0, CF_COK, void, do_return, (void),)
  1362. {
  1363.     char   buf[MAXLINELEN];
  1364.     char * partial;
  1365.  
  1366.     if (GETF_COMLINEMODE(Ep))
  1367.     {
  1368.     strcpy (buf, (char *)Current);
  1369.  
  1370.     partial = esc_partial;    /* PATCH_NULL: P -> esc_p */
  1371.     esc_partial = NULL;    /* PATCH_NULL: P -> esc_p */
  1372.  
  1373.     escapecomlinemode ();
  1374.  
  1375.     if (partial)
  1376.     {
  1377.         if (do_command (buf))
  1378.         do_command (partial);
  1379.  
  1380.         free(partial);
  1381.     } else
  1382.         do_command (buf);
  1383.     } else
  1384.     {
  1385.     if (GETF_AUTOINDENT(Ep))
  1386.     {   /* If user want's autoindent */
  1387.         WORD   indent;  /* how much */
  1388.         WORD   line;    /* Line-no. */
  1389.         char * ptr;     /* pointer to Ep->list[line] */
  1390.  
  1391.         text_sync ();   /* store actual line */
  1392.  
  1393.         /* Start with current line */
  1394.         indent = 0;
  1395.         ptr = (char *)Current;
  1396.  
  1397.         /* Find 1. nonspace ... */
  1398.         while (isspace (*ptr))
  1399.         {
  1400.         ptr ++;
  1401.         indent ++;
  1402.         }
  1403.  
  1404.         /* ... but not '\0'. In this case the line is empty and
  1405.            indent is therefore 0 */
  1406.         if (!*ptr)
  1407.         indent = 0;
  1408.  
  1409.         /* Try on, if indent is zero, line is empty and there are more
  1410.            lines on top */
  1411.         if (!indent && !*ptr && Ep->line)
  1412.         {
  1413.         line = Ep->line - 1;
  1414.  
  1415.         /* Until 1. line */
  1416.         while (line)
  1417.         {
  1418.             /* Try every line */
  1419.             ptr = GETTEXT(Ep,line);
  1420.             indent = 0;
  1421.  
  1422.             while (isspace (*ptr))
  1423.             {
  1424.             ptr ++;
  1425.             indent ++;
  1426.             }
  1427.  
  1428.             if (indent || *ptr)
  1429.             break;
  1430.  
  1431.             line --;
  1432.         }
  1433.         }
  1434.  
  1435.         /* Not at last position in line ? then we have to split and
  1436.            indent the rest */
  1437.         if (Ep->column != Clen)
  1438.         {
  1439.         /* Split line, move to next line but shouldn't show this */
  1440.         do_split ();
  1441.         do_down ();
  1442.  
  1443.         /* Indent new line */
  1444.         if (indent > Ep->column)
  1445.             indent -= indent - Ep->column;
  1446.  
  1447.         if (indent > 0)
  1448.         {
  1449.             movmem (Current, Current+indent, Clen+1);
  1450.             setmem (Current, indent, ' ');
  1451.             Clen += indent;
  1452.             Ep->column = indent;
  1453.         } else
  1454.             Ep->column = 0;
  1455.  
  1456.         Current[Clen] = 0;
  1457.  
  1458.         /* and position cursor */
  1459.         text_sync ();
  1460.  
  1461.         /* Show result */
  1462.         text_redisplaycurrline ();
  1463.         } else
  1464.         {
  1465.         if (Ep->line != Ep->lines-1)
  1466.         {
  1467.             do_down ();
  1468.             do_insline ();
  1469.  
  1470.             Ep->column = indent;
  1471.             text_sync ();
  1472.         } else
  1473.         {
  1474.             do_split ();
  1475.             Ep->column = indent;
  1476.             text_sync ();
  1477.             do_down ();
  1478.         }
  1479.         }
  1480.     } else
  1481.     {
  1482.         Ep->column = 0;
  1483.         text_sync ();
  1484.         do_downadd ();
  1485.     }
  1486.     } /* !Comlinemode */
  1487. } /* do_return */
  1488.  
  1489.  
  1490. /******************************************************************************
  1491. *****  ENDE edit.c
  1492. ******************************************************************************/
  1493.